#ifndef CONFIG_H
#define CONFIG_H

#include <string>
#include <list>
#include <vector>
#include <map>
#include <fstream>

#include "variant.h"
#include "configgroup.h"

using namespace std;


/**
 * Represents a configuration file in memory.
 */
class Config
{
	friend class ConfigGroup;
	public:
		/**
		 * The constructor opens and reads the configuration file. If the file
		 * doesn't exist it doesn't create it until @see sync() is called.
		 * 
		 * @param path This must point to the place where the file is.
		 * @param perm A config file can be opened either as read/write with
		 *             perm set to "rw" or read only if perm is "r". By default
		 *             it's read/write, and if an erronous mode is set, it will
		 *             be opened as read/write. If the file is read only, it
		 *             will always be opened as read only.
		 */
		Config(string path, string perm = "rw");

    /**
      * This constructor don't use a configuration file, so the objets is
      * empty at first. Later you can specify a file with @see setPath()
      */
    Config();

		/**
		 * Destructor. Calls to @see sync and closes the file.
		 */
		virtual ~Config();

		/**
		 * Returns the file path which represents this config file.
		 */
		string path();

    /**
      * Set the actual path where configuration file is saved.
      * If the file exists, it will be OVERWRITE and all data inside
      * will be DELETED.
      *
      * @returns True if the file could be open in write mode.
      */
    void setPath(string path);

		/**
		 * Writes this configuration file to disk. No configuration is saved to
		 * disk until this function is called. You must call it manualy, it's
		 * not done automatically. If writeable option is false it doesn't write
     * in the file.
     *
     * @returns False if there isn't a path or it's read only.
		 */
		bool sync();

		/**
		 * Returns whether a group exists or not.
		 */
		bool hasGroup(const string& name);

		/**
		 * Returns a list containing the names of the top-level groups inside
		 * this config file.
		 */
		list<string> groupList();

		/**
		 * Deletes a group and all its content (keys, subgroups) if it exists.
		 * If the group doesn't exists, it does nothing.
		 */
		void deleteGroup(const string& name);

		/**
		 * Access to a top level config group by name. If the group doesn't
		 * exists it creates it, but when you call to nonExistentGroup.exists() 
		 * it will return false, and it will also be empty.
		 */
		ConfigGroup& operator[](const string& groupName);

        
    /**
     * Trims spaces and removes everything after a comment if wanted
     */
    static string trimLine(const string& line, bool stripComments = true);

    /**
      * Set if the file must be written.
      */ 
    void setWriteable(const bool option);

    /**
      * Returns if the file must be written.
      */
    bool isWriteable();

	protected:
		/**
		 * Parses the configuration file. Only called by the constructor.
		 */
		void reparseConfiguration();

		string m_filePath;
		map<string, ConfigGroup*> m_groups;
		bool m_writeable;
		fstream m_file;
};

#endif
